Перейти к основному содержимому

5.16. Первая программа

Разработчику Архитектору

Первая программа

Ассемблер — это язык программирования низкого уровня, максимально приближенный к машинному коду, который исполняет процессор. Каждая команда на ассемблере соответствует одной или нескольким инструкциям процессора. Это позволяет программисту управлять аппаратными ресурсами напрямую: регистрами центрального процессора, памятью, прерываниями и портами ввода-вывода.

Программы на ассемблере обладают высокой производительностью и минимальным размером. Они находят применение в системном программировании, разработке драйверов устройств, встраиваемых системах, операционных системах, а также в задачах, где критичны скорость и контроль над оборудованием. Изучение ассемблера даёт глубокое понимание того, как работает компьютер на самом низком уровне — от загрузки программы до выполнения каждой инструкции.

Архитектура и диалекты

Ассемблер не является единым языком. Он зависит от архитектуры процессора. Наиболее распространённые архитектуры для обучения — x86 и x86-64 (Intel/AMD), используемые в большинстве персональных компьютеров. Для этих архитектур существуют два основных синтаксических стиля:

  • Intel Syntax — используется в большинстве учебных материалов, отладчиков Windows и популярных ассемблеров, таких как MASM и NASM.
  • AT&T Syntax — применяется в Unix-подобных системах, особенно в связке с GCC и GAS (GNU Assembler).

Для начала рекомендуется использовать Intel Syntax, так как она более интуитивна для новичков: операнды указываются в порядке «назначение, источник», а регистры и константы записываются без лишних префиксов.

Можно ли писать на ассемблере в Windows

Да, написание и запуск программ на ассемблере возможны в операционной системе Windows. Для этого требуется установить комплект инструментов, включающий ассемблер, компоновщик (линкер) и, при необходимости, отладчик. Современные версии Windows поддерживают 64-битное программирование, но многие учебные примеры построены на 32-битной модели, так как она проще для понимания и имеет меньше ограничений со стороны операционной системы.

Необходимые инструменты

Для написания первой программы на ассемблере в Windows понадобятся следующие компоненты:

1. Ассемблер

Наиболее подходящий выбор для начинающих — NASM (Netwide Assembler). Это свободный, кроссплатформенный ассемблер, поддерживающий Intel Syntax и генерирующий объектные файлы в форматах COFF (для Windows) и ELF (для Linux). NASM активно поддерживается, имеет простой синтаксис и обширную документацию.

2. Компоновщик (Linker)

После ассемблирования исходного кода получается объектный файл, который необходимо объединить с системными библиотеками и оформить в исполняемый файл. В Windows для этой цели используется link.exe из Microsoft Visual Studio Build Tools или ld из MinGW-w64.

Для упрощения процесса рекомендуется установить MinGW-w64 — набор инструментов GNU для Windows, включающий компилятор GCC, ассемблер GAS, компоновщик ld и другие утилиты. Однако для работы с NASM удобнее использовать link.exe из официальных инструментов Microsoft.

3. Текстовый редактор или IDE

Ассемблер не требует сложной среды разработки. Достаточно любого текстового редактора, поддерживающего подсветку синтаксиса, например:

  • Visual Studio Code с расширением для NASM,
  • Notepad++,
  • Sublime Text.

Полноценные IDE, такие как SASM (SimpleASM), специально созданы для обучения ассемблеру. SASM включает встроенный NASM, компоновщик, отладчик и окно вывода, что делает его идеальным выбором для первых шагов.

4. Отладчик (опционально, но полезно)

Для анализа выполнения программы можно использовать x64dbg — современный отладчик для Windows, поддерживающий как 32-, так и 64-битные приложения. Он позволяет просматривать регистры, память, стек и пошагово выполнять инструкции.

Пошаговая установка инструментов

Шаг 1: Установка SASM (рекомендуемый способ для новичков)

  1. Перейдите на официальный сайт SASM: https://dman95.github.io/SASM/
  2. Скачайте установщик для Windows.
  3. Запустите установщик и следуйте инструкциям.
  4. После установки откройте SASM. По умолчанию он настроен на использование NASM и генерацию 32-битных программ под Windows.

SASM автоматически устанавливает всё необходимое: ассемблер, компоновщик, среду выполнения. Это избавляет от необходимости настраивать пути и команды вручную.

Шаг 2: Альтернативная установка (вручную)

Если вы предпочитаете полный контроль:

  1. Скачайте NASM с официального сайта: https://www.nasm.us/

    • Выберите Windows-версию (обычно это ZIP-архив).
    • Распакуйте содержимое в папку, например C:\nasm.
    • Добавьте эту папку в переменную среды PATH.
  2. Установите Microsoft Visual Studio Build Tools:

    • Перейдите на страницу загрузки Visual Studio.
    • Выберите «Build Tools for Visual Studio».
    • В установщике отметьте компонент «C++ build tools», включающий link.exe.
  3. Убедитесь, что в командной строке доступны команды nasm и link.

Написание первой программы: Hello, World!

Программа на ассемблере для Windows может использовать системные вызовы через API Win32. Простейший способ вывести текст — вызвать функцию MessageBoxA из библиотеки user32.dll.

Ниже приведён пример программы на 32-битном ассемблере с использованием NASM-синтаксиса:

section .data
msg db 'Hello, World!', 0
caption db 'My First ASM Program', 0

section .text
global _start
extern _MessageBoxA@16
extern _ExitProcess@4

_start:
; Вызов MessageBoxA(hWnd, lpText, lpCaption, uType)
push 0 ; uType = MB_OK
push caption ; lpCaption
push msg ; lpText
push 0 ; hWnd = NULL
call _MessageBoxA@16

; Завершение программы
push 0 ; exit code
call _ExitProcess@4

Этот код делает следующее:

  • Определяет две строки в секции данных: сообщение и заголовок окна.
  • В секции кода вызывает функцию MessageBoxA из Windows API.
  • После закрытия окна вызывает ExitProcess для корректного завершения.

Сборка и запуск вручную

Если вы используете NASM и link.exe вручную, выполните следующие команды в командной строке:

  1. Ассемблирование:

    nasm -f win32 hello.asm -o hello.obj
  2. Компоновка:

    link /subsystem:windows /entry:_start hello.obj user32.lib kernel32.lib

В результате будет создан исполняемый файл hello.exe, который можно запустить двойным щелчком.

Сборка и запуск в SASM

  1. Откройте SASM.
  2. Создайте новый файл.
  3. Вставьте приведённый выше код.
  4. Нажмите кнопку Run (или F9).
  5. Появится окно с надписью «Hello, World!».

SASM автоматически обрабатывает все этапы сборки и подключает необходимые библиотеки.

Особенности 64-битного программирования

В 64-битной Windows системные вызовы через WinAPI работают иначе: соглашение о вызовах меняется, параметры передаются через регистры, а не через стек. Для первого знакомства рекомендуется начинать с 32-битного режима, так как он проще и лучше документирован в учебных материалах.


Структура программы на ассемблере

Программа на ассемблере состоит из логических блоков, называемых секциями. Каждая секция содержит определённый тип данных или инструкций. Наиболее важные секции в программе для Windows:

  • .data — содержит инициализированные данные: строки, числа, константы.
  • .bss — содержит неинициализированные данные (например, буферы, массивы, которые будут заполнены позже).
  • .text — содержит исполняемый код, то есть последовательность машинных инструкций.

Эти секции отражают внутреннюю организацию исполняемого файла и соответствуют сегментам памяти, выделяемым операционной системой при запуске программы.

Регистры процессора

Центральный процессор использует небольшие сверхбыстрые ячейки памяти — регистры — для временного хранения данных и адресов. В архитектуре x86 основные 32-битные регистры включают:

  • EAX, EBX, ECX, EDX — общего назначения,
  • ESI, EDI — индексные регистры для работы со строками и массивами,
  • ESP — указатель стека,
  • EBP — базовый указатель для доступа к параметрам функций.

В 64-битном режиме регистры расширяются до 64 бит (RAX, RBX и так далее), но для первых шагов достаточно понимания 32-битной модели.

Регистры играют роль переменных самого низкого уровня. Все операции в ассемблере выполняются над регистрами или между регистром и памятью.

Стек и вызовы функций

Стек — это область памяти, используемая для передачи параметров в функции, хранения локальных переменных и возврата управления после вызова. Операции push и pop добавляют и извлекают значения из стека.

При вызове функции через call процессор автоматически помещает в стек адрес возврата. Функция завершается командой ret, которая извлекает этот адрес и передаёт управление обратно вызывающему коду.

В Windows API функции используют соглашение о вызовах stdcall, при котором параметры передаются через стек в обратном порядке (справа налево), а очистка стека выполняется самой функцией. Это отличает их от соглашения cdecl, где очистка стека лежит на вызывающей стороне.

Имена функций в 32-битном stdcall имеют специальный суффикс вида @N, где N — общее количество байт параметров. Например, _MessageBoxA@16 означает, что функция принимает 16 байт аргументов (четыре 32-битных параметра).

Понимание имён и экспорта

Ключевое слово global _start указывает ассемблеру, что метка _start является точкой входа в программу. Компоновщик ищет именно эту метку, чтобы определить, с какого места начинать выполнение.

Ключевое слово extern объявляет, что функция определена вне текущего файла — в системной библиотеке. Например, _MessageBoxA@16 находится в user32.dll, а _ExitProcess@4 — в kernel32.dll. При компоновке эти имена связываются с реальными адресами в памяти.

Альтернативный подход: DOS и эмуляторы

Если использовать современный Windows API кажется сложным, можно начать с эмуляции старой среды MS-DOS. Для этого подходит эмулятор DOSBox вместе с ассемблером TASM или MASM, а также утилитой LINK.EXE из пакета Microsoft Macro Assembler.

Пример простой программы для DOS:

section .text
global _start

_start:
mov ah, 09h ; функция вывода строки
mov dx, msg ; адрес строки
int 21h ; вызов DOS

mov ah, 4Ch ; завершение программы
mov al, 0 ; код возврата
int 21h

section .data
msg db 'Hello, World!$'

Здесь используется прерывание DOS int 21h для вывода текста. Строка должна заканчиваться символом $. Такой код нельзя запустить напрямую в современной Windows, но он отлично работает в DOSBox или через эмулятор emu8086.

Этот подход полезен для обучения, так как исключает необходимость взаимодействия с современными библиотеками и позволяет сосредоточиться на базовых инструкциях процессора.

Отладка первой программы

После успешного запуска программы полезно заглянуть «внутрь» её выполнения. Отладчик x64dbg позволяет:

  • поставить точку останова на метке _start,
  • просматривать содержимое регистров до и после каждой инструкции,
  • наблюдать, как изменяется стек при вызове call,
  • видеть, какие системные библиотеки загружены в память.

Даже простой просмотр того, как адрес строки передаётся в стек, даёт ощущение контроля над машиной.